﻿// -----------------------------------------------------------------------
// <copyright file="DirectLambdaExpression.cs" company="none">
// Copyright (c) 2012 M. Alberti, xanatos(at)live.it
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// </copyright>
// -----------------------------------------------------------------------

namespace FluentSerializer.Utilities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;

    /// <summary>
    /// 
    /// </summary>
    public class DirectLambdaExpression : ExpressionVisitor
    {
        /// <summary>
        /// 
        /// </summary>
        protected readonly Dictionary<ParameterExpression, Expression> Parameters;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parameters"></param>
        protected DirectLambdaExpression(Dictionary<ParameterExpression, Expression> parameters)
        {
            this.Parameters = parameters;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="lambda"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static Expression Prepare(LambdaExpression lambda, IEnumerable<Expression> parameters)
        {
            Expression expression = new DirectLambdaExpression(lambda.Parameters.Zip(parameters, (p, q) => new { Key = p, Value = q }).ToDictionary(p => p.Key, p => p.Value)).Visit(lambda.Body);
            return expression;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="lambda"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static Expression Prepare(LambdaExpression lambda, params Expression[] parameters)
        {
            if (lambda.Parameters.Count != parameters.Length)
            {
                throw new NotSupportedException();
            }

            Expression expression = new DirectLambdaExpression(lambda.Parameters.Zip(parameters, (p, q) => new { Key = p, Value = q }).ToDictionary(p => p.Key, p => p.Value)).Visit(lambda.Body);
            return expression;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        protected override Expression VisitParameter(ParameterExpression node)
        {
            Expression replace;

            if (this.Parameters.TryGetValue(node, out replace))
            {
                return replace;
            }

            return base.VisitParameter(node);
        }
    }
}